﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using TAC;

namespace MenuTeste
{
    class NPC
    {
        /**
         * Estrutura criada para armazenar de forma
         * mais simples a posicao dos avaters no campo
         * de batalha.
         * Um Vector2 não seria adequado, pois este trabalha
         * com ponto flutuante. Como as posicoes sao restritamente
         * coordenadas expressas em numeros inteiros, criamos essa
         * estrutura para evitar conversoes de tipo indesejadas. 
         */
        public class Coordinates {
            public int X;
            public int Y;
            public Coordinates(int i, int j)
            {
                X = i;
                Y = j;
            }
        }

        // Tamanho da unidade basica representavel no campo.         
        private Vector2 CELLSIZE = new Vector2(0.35f, 0.4f);
        
        // Dispositivo utilizado para operacoes graficas.
        private GraphicsDevice device;
        
        // Matriz que guarda as coordenadas do mundo.
        public Matrix worldMatrix = Matrix.Identity;
        
        // Posicao do jogador no mundo.
        private Vector3 position = Vector3.Zero;
        
        // Posicao do jogador no tabuleiro.
        Coordinates MatrixPosition;
        
        // Frame corrente da animacao.
        int frame = 0;
        
        // Constante do scale aplicado aos NPCs.
        const float SCALE = 0.007f;
        
        // Numero de frames da animacao.
        const int NUMBEROFFRAMES = 100;
        
        // Constantes que indicam a animacao a ser realizada. 
        bool MOVE = false, ATTACKED = false, SUPERATTACKED = false;

        float radiansanglerotation = 0.0f;

        public readonly NonPlayerCharacter character;
        Coordinates MoveIndex = new Coordinates(0,0);
        bool alreadydecided = false;
        Vector3 PositionZero = new Vector3(-1.62f, -0.25f, -2.1f);
        Vector3 PreviousPosition;
        //-1.7f, -0.25f, -3.0f

        Model myModel;

        public void Decided() { alreadydecided = true; }

        public bool IsDone() 
        {
            return (frame == NUMBEROFFRAMES);
        }

        public bool AlreadyDecided()
        {
            return alreadydecided;
        }

        public void Reset() 
        {
            frame = 0;
            alreadydecided = false;
            MOVE = false;
            ATTACKED = false;
            SUPERATTACKED = false;
        }

        public int GetXMatrixIndex() { return MatrixPosition.X; }
        public int GetYMatrixIndex() { return MatrixPosition.Y; }

        public void Move(int i, int j) 
        {
            if ((ATTACKED) || (SUPERATTACKED))
                return;

            MOVE = true;
            MoveIndex.X = i;
            MoveIndex.Y = j;
            MatrixPosition = MoveIndex;
            alreadydecided = true;
            PreviousPosition = position;
            character.setX(i);
            character.setY(j);
        }

        public void Atacked() 
        {
            if ((MOVE) || (SUPERATTACKED))
                return;
            
            ATTACKED = true;
            PreviousPosition = position;

        }

        public void SuperAttacked()
        {
            if ((MOVE) || (ATTACKED))
                return;

            SUPERATTACKED = true;
            PreviousPosition = position;

        }

        public void Update(GameTime gameTime) 
        {
            if (MOVE)
            {
                Vector3 increment, next;
                float distance;

                next = new Vector3(MoveIndex.Y * (CELLSIZE.X - CELLSIZE.X / 20.0f) + CELLSIZE.X / 2.0f
                    , 0.0f, MoveIndex.X * (CELLSIZE.Y - CELLSIZE.Y / 6.0f) + CELLSIZE.Y / 2.0f);

                next += PositionZero;

                distance = Vector3.Distance(next, position);

                increment = (next - PreviousPosition)/100.0f;
                
                position.Y = 0.35f;

                if (frame < NUMBEROFFRAMES)
                {
                    frame++;
                    
                    position += increment;
                }
            }
            else if (ATTACKED) 
            {
                Vector3 positionaux = new Vector3(0.004f, 0.0f, 0.0f);

                if (frame % 3 == 0)
                {
                    positionaux *= -1;
                    radiansanglerotation = MathHelper.ToRadians(2);
                }
                else
                    radiansanglerotation = MathHelper.ToRadians(-2);

                position = PreviousPosition + positionaux;
                frame++;
                if (IsDone())
                {
                    position = PreviousPosition;
                    radiansanglerotation = 0.0f;
                }
            
            }
            else if (SUPERATTACKED) 
            {
                Vector3 positionaux = new Vector3(0.004f, 0.0f, 0.0f);

                if (frame % 3 == 0)
                {
                    positionaux *= -1;
                    radiansanglerotation = MathHelper.ToRadians(5);
                }
                else
                    radiansanglerotation = MathHelper.ToRadians(-5);

                position = PreviousPosition + positionaux;
                frame++;
                if (IsDone())
                {
                    position = PreviousPosition;
                    radiansanglerotation = 0.0f;
                }
            }
        }

        public void SetPosition(int i, int j)
        {
            position = PositionZero + new Vector3(j * (CELLSIZE.X-CELLSIZE.X / 20.0f) + CELLSIZE.X / 2.0f
               , 0.0f, i * (CELLSIZE.Y - CELLSIZE.Y / 6.0f) + CELLSIZE.Y / 2.0f);

            position.Y = 0.35f;

        }

        public NPC(GraphicsDevice graphicsDevice, NonPlayerCharacter character)
        {
            this.character = character;
            device = graphicsDevice;
            frame = 0;
            MOVE = false;
            alreadydecided = false;
            MatrixPosition = new Coordinates(character.getX(),character.getY());
            SetPosition(MatrixPosition.X, MatrixPosition.Y);
        }

        public void LoadContent(Model mModel)
        {
            // Calculate the effect aspect ratio, projection, and view matrix
            float aspectRatio = (float)device.Viewport.Width / device.Viewport.Height;
            this.myModel = mModel;

            foreach (ModelMesh mesh in myModel.Meshes)
                foreach (BasicEffect effect in mesh.Effects)
                {
                    // Set the projection matrix for the model
                    effect.Projection = Matrix.CreatePerspectiveFieldOfView(
                    MathHelper.ToRadians(45.0f),
                    aspectRatio, 1.0f, 20.0f);
                    effect.View = Matrix.CreateLookAt(new Vector3(0.0f, 2.0f, 3.5f),
                    Vector3.Zero, Vector3.Up);
                    effect.EnableDefaultLighting();
                }
            
            SetPosition(MatrixPosition.X, MatrixPosition.Y);
        }

        public void UnloadContent()
        {
        }

        public void Draw()
        {
            // Loop through each mesh of the model
            foreach (ModelMesh mesh in myModel.Meshes)
            {   
                // Draw the current mesh
                
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.World = Matrix.CreateScale(SCALE) *
                    Matrix.CreateRotationZ(radiansanglerotation) * Matrix.CreateTranslation(position);
                }

                mesh.Draw();
            }
        }
    }
}
